package com.stark.wechat.service.signature;

import com.stark.wechat.core.Config;
import lombok.Builder;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 签名接口
 *
 * @author <a href="mailto:mengbin@hotmail.com">Ben</a>
 * @version 1.0.0
 * @see <a href="https://developers.weixin.qq.com/doc/service/guide/dev/push/encryption.html">开发指南 / 消息与事件推送 / 消息加解密说明</a>
 * @since 2024/5/23
 */
@Builder
public class SignatureService {

    private Config config;

    /**
     * 校验明文模式签名
     *
     * @param signature 微信加密签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @return 是否校验通过
     */
    public boolean validate(String signature, String timestamp, String nonce) {
        // 1）将token、timestamp、nonce三个参数进行字典序排序
        List<String> items = new ArrayList<>();
        items.add(config.getToken());
        items.add(timestamp);
        items.add(nonce);
        items.sort(String::compareTo);

        // 2）将三个参数字符串拼接成一个字符串进行sha1加密
        String str = StringUtils.join(items, "");
        String strEncrypted = DigestUtils.sha1Hex(str);

        // 3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        return strEncrypted.equalsIgnoreCase(signature);
    }

    /**
     * 校验安全模式签名
     *
     * @param msgSignature 微信加密签名
     * @param timestamp    时间戳
     * @param nonce        随机数
     * @param encrypt      包体内的 <i>Encrypt</i> 字段
     * @return 是否校验通过
     */
    public boolean validate(String msgSignature, String timestamp, String nonce, String encrypt) {
        // 1）将token、timestamp、nonce、Encrypt四个参数进行字典序排序
        List<String> items = new ArrayList<>();
        items.add(config.getToken());
        items.add(timestamp);
        items.add(nonce);
        items.add(encrypt);
        items.sort(String::compareTo);

        // 2）将四个参数字符串拼接成一个字符串进行sha1加密
        String str = StringUtils.join(items, "");
        String strEncrypted = DigestUtils.sha1Hex(str);

        // 3）开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        return strEncrypted.equalsIgnoreCase(msgSignature);
    }

    /**
     * 签名
     *
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param encrypt   加密后的消息体
     * @return 签名
     */
    public String sign(long timestamp, String nonce, String encrypt) {
        // 1）将token、timestamp、nonce、Encrypt四个参数进行字典序排序
        List<String> items = new ArrayList<>();
        items.add(config.getToken());
        items.add(String.valueOf(timestamp));
        items.add(nonce);
        items.add(encrypt);
        items.sort(String::compareTo);

        // 2）将四个参数字符串拼接成一个字符串进行sha1加密
        String str = StringUtils.join(items, "");
        return DigestUtils.sha1Hex(str);
    }

}
